home *** CD-ROM | disk | FTP | other *** search
- PAGE 59, 132
-
- TITLE MSXIBM -- Machine dependent module for IBM-PC, except Terminal
-
- ; Update 4 Jan 86
-
- IF1
- %OUT >> Starting pass 1
- ELSE
- %OUT >> Starting pass 2
- ENDIF
-
- PUBLIC SerIni_PC, SerRst_PC, ClrBuf_PC, OutChr_PC, Coms_PC
- ; PUBLIC VTS_PC
- PUBLIC DoDel_PC, CtlU_PC, CmBlnk_PC, Locate_PC, PrtChr_PC, DoBaud_PC
- PUBLIC ClearL_PC, DoDisk_PC, GetBaud_PC, Beep_PC
- PUBLIC PutHlp_PC, PutMod_PC, PutErr_PC, ClrMod_PC, PosCur_PC
- PUBLIC SendBr_PC, SetKTab_PC, SetKHlp_PC, LclIni_PC, ShowKey_PC
- PUBLIC Which_card, Drop_DTR_PC, Which_page, Beam_Off, Beam_On
- PUBLIC Set_up_video_card_pointers, CRT_Mode
-
- INCLUDE msdefs.h
-
- false EQU 0
- true EQU 1
- Screen EQU 10h ; BIOS screen call
-
- XOFF_trigger_count EQU BufSiz*2 / 3 ; High point = 2/3 of buffer full
-
- Mode_control_port EQU 3D8h ; CRT mode control port
- Video_enable EQU 8 ; Display enable flag
-
- Number_of_rows EQU 24 ; Length in rows
- Number_of_columns EQU 80 ; Width in characters
- Highest_row EQU Number_of_rows-1; Highest row number
- Highest_column EQU Number_of_columns-1 ; Highest column number
- Number_of_rows_PC EQU 25 ; Length in rows including mode line
-
- ; constants used by serial port handler
-
- BRKBIT EQU 40h ; Send-break bit
- TIMER EQU 40h ; Use to issue short beep
- PORT_B EQU 61h ; Port B address
- MCONF EQU 11h ; Machine configuration
- KEYB EQU 16h
- BIOS EQU 10h
-
- MDMDAT1 EQU 03F8h ; Address of modem port 1 data register
- MDMSTS1 EQU 03FDh ; Address of modem port 1 status register
- MDMCOM1 EQU 03FBh ; Address of modem port 1 command register
-
- MDMDAT2 EQU 02F8h ; Port 2 address register
- MDMSTS2 EQU 02FDh ; Port 2 status register
- MDMCOM2 EQU 02FBh ; Port 2 command register
-
- MDMINP EQU 1 ; Input ready bit
-
- MDMINTV EQU 0030h ; Address of modem port interrupt vector
- MDINTV2 EQU 002Ch ; Address for port 2
-
- MDMINTO EQU 0EFh ; Mask to enable interrupt for modem port
- MDINTO2 EQU 0F7h ; Enable interrupt level 3
-
- MDMINTC EQU 010h ; Bit to set to disable interrupts for modem
- MDINTC2 EQU 008h ; Disable IRQ3
-
- INTCONT EQU 0021h ; Address of 8259 interrupt controller ICW2-3
- INTCON1 EQU 0020h ; Address of 8259 ICW1
-
- EOICOM EQU 0064h ; End of interrupt
- EOICOM2 EQU 0063h ; End of interrupt for COM2
-
-
- ; external variables used:
- ; drives - # of disk drives on system
- ; flags - global flags as per flginfo structure defined in pcdefs
- ; trans - global transmission parameters, trinfo struct defined in pcdefs
- ; portval - pointer to current portinfo structure (currently either port1
- ; or port2)
- ; port1, port2 - portinfo structures for the corresponding ports
-
- ; global variables defined in this module:
- ; xofsnt, xofrcv - tell whether we saw or sent an xoff
- ; setktab - keyword table for redefining keys (should contain a 0 if
- ; not implemented)
- ; setkhlp - help for setktab
-
- DataS SEGMENT PUBLIC 'DataS'
-
- EXTRN drives:byte,flags:byte, trans:byte, PC_Subtype:BYTE
- EXTRN portval:word, port1:byte, port2:byte
- EXTRN Count:WORD, XofSnt:BYTE, Force_mono:BYTE, Force_card:BYTE
- EXTRN Source:BYTE, SrcPnt:WORD, PC_Type:BYTE
-
- PUBLIC Video_page_addresses
-
- Video_page_addresses LABEL WORD
- DW 0B800h ; Page zero
- DW 0B900h ; Page one
-
- SetKTab_PC DB 12
- mkeyw 'BACKSPACE',0eh
- mkeyw 'F1',3bh
- mkeyw 'F2',3ch
- mkeyw 'F3',3dh
- mkeyw 'F4',3eh
- mkeyw 'F5',3fh
- mkeyw 'F6',40h
- mkeyw 'F7',41h
- mkeyw 'F8',42h
- mkeyw 'F9',43h
- mkeyw 'F10',44h
- mkeyw 'SCAN',-1
-
- SetKHlp_PC DB cr,lf,'Keyname: backspace, f1, ... f10, or "SCAN" followed by '
- DB 'decimal scan code$'
- brkval DB 0 ; What to send for a break
- brkadr DW 0 ; Where to send it
- modem mdminfo <MDMDAT1,MDMSTS1,MDMCOM1,MDMINTO,MDMINTC,EOICOM,MDMINTV>
- erms20 DB '? Warning: System has no disk drives', Cr, Lf, '$'
- erms40 DB '? Warning: Unrecognized baud rate', Cr, Lf, '$'
- badbd DB 'Unimplemented baud rate', Cr, Lf, '$'
- No_memory DB '? Not enough memory for program to run (screen management)'
- DB Cr, Lf, '$'
- crlf DB cr,lf,'$'
- delstr DB BS,' ',BS,'$' ; Delete string. [21d]
- clrlin DB cr,'$' ; Clear line (just the cr part)
- savsci DW ? ; Save for serial port interrupt vector. [14]
- savscs DW ? ; Ditto. [14]
- savbr1 DW ? ; "Break" interrupt vector. [25]
- savbr2 DW ? ; Ditto. [25]
- portin DB 0 ; Has comm port been initialized. [21c]
- xofrcv DB 0 ; Say if we received an XOFF
- tmp DB ?,'$'
- temp DW 0
- temp1 DW ? ; Temporary storage
- temp2 DW ? ; Temporary storage
-
- CRT_Mode DB 7 ; Crt mode for video card
- Which_page DB 0 ; Video page number
- Screen_pointer DW 0B000h ; Pointer to real screen memory
-
- Beam_status DB ? ; Place to hold CRT status reg value
-
- ontab DB 02H ; Two entries
- DB 03H,'OFF$' ; Should be alphabetized. [19a]
- DW 00H
- DB 02H,'ON$'
- DW 01H
-
- comptab DB 04H
- DB 01H,'1$'
- DW 01H
- DB 01H,'2$'
- DW 00H
- DB 04H,'COM1$'
- DW 01H
- DB 04H,'COM2$'
- DW 00H
-
- ; this table is indexed by the baud rate definitions given in
- ; pcdefs. Unsupported baud rates should contain FF
-
- bddat label word
- DW 0FFH ; 45.5 baud -- Not supported
- DW 900H ; 50 baud
- DW 600H ; 75 baud
- DW 417H ; 110 baud
- DW 359H ; 134.5 baud
- DW 300H ; 150 baud
- DW 180H ; 300 baud
- DW 0C0H ; 600 baud
- DW 60H ; 1200 baud
- DW 40H ; 1800 baud
- DW 3AH ; 2000 baud
- DW 30H ; 2400 baud
- DW 18H ; 4800 baud
- DW 0CH ; 9600 baud
- DW 06h ; 19200 baud
- DW 03h ; 38400 baud
- DW 05h ; 23040 baud
-
- ; variables for serial interrupt handler
-
- savesi DW 0 ; Save SI register here
- telflg DB 0 ; Are we acting as a terminal
- mst DW 0 ; Modem status address
- mdat DW 0 ; Modem data address
- mdeoi DB 0 ; End-of-Interrupt value
-
- rbtrn DB 7fH ; rubout
-
- shkbuf DB 300 dup (?) ; room for definition
- shkmsg DB ' Scan code: '
- shkmln EQU $-shkmsg
- shkms1 DB cr,lf,' Definition: '
- shkm1ln EQU $-shkms1
-
- DataS ENDS
-
- Code SEGMENT PUBLIC
-
- EXTRN Comnd:near, dopar:near, defkey:near, gss:near
- EXTRN Set_up_dynamic_memory:NEAR, Exit2:NEAR, NoInt:NEAR, OkInt:NEAR
- EXTRN Write_to_standard_output:NEAR
-
- ASSUME cs:Code, ds:DataS
-
- Which_card DB 0 ; 0 for mono, 1 for color, 2 for EGA
-
- ; local initialization
-
- LclIni_PC proc near
-
- call Set_up_dynamic_memory ; Try to get memory
- jnc LCL_0
-
- mov ah, PrStr ; Code to type message
- mov dx, OFFSET No_memory ; Complain about lack of memory
- int Dos ; Display it
-
- call Exit2 ; Bomb out also
- nop
- nop
- nop
-
- ret ; Return to main program
-
- LCL_0: mov ax,0eH ; scan code for arrow key
- mov si,offset rbtrn ; translate to rubout
- mov cx,1 ; one char translation
- call defkey
- mov brkval,BRKBIT ; What to send for a break
- mov ax,modem.mdcom ; Where to send it
- mov brkadr,ax
-
- call Set_up_video_card_pointers
- jmp Go_to_page_zero
-
- LclIni_PC endp
-
-
- Set_up_video_card_pointers PROC
-
- mov ah, 15 ; Code to read current video mode
- int Screen ; Read it
-
- mov CRT_Mode, al ; Save crt mode
-
- sub ah, ah ; Set flag for mono
- mov Which_page, ah ; Zero the page number
-
- cmp Force_card, 0FFh ; Are we forcing some card type?
- je SUV_0 ; No, keep checking
-
- mov ah, Force_card ; Pick up forced value
- mov Which_card, ah ; Save it
- ret ; That's it
-
- SUV_0: cmp al, 7 ; Is it really color?
- je SUV_1 ; Ok, it is monochrome
-
- mov ah, 1 ; Flag for color card
-
- SUV_1: mov Which_card, ah ; Remember which card we are using
- cmp ah, 1 ; Did we just decide that this is a color card?
- je Check_for_EGA ; See if we are on the Enhanced card
-
- ret ; That's it
-
- Set_up_video_card_pointers ENDP
-
-
- ; See if we are using the Enhanced Graphics Adapter
-
- Check_for_EGA PROC
-
- cmp PC_Type, 0 ; We won't even bother without PC-DOS
- jne CEG_Done ; Not running PC-DOS, assume not EGA
-
- cmp PC_Subtype, 0 ; Are we on a normal PC?
- je CEG_PC ; Yes
-
- cmp PC_Subtype, 1 ; Are we on an XT?
- je CEG_XT ; Yes
-
- cmp PC_Subtype, 4 ; ... or a Portable (same motherboard as XT)?
- je CEG_XT ; Yes
-
- cmp PC_Subtype, 3 ; Are we on an AT?
- je CEG_AT ; Yes
-
- ; jmp CEG_Done ; No way of knowing about EGA, assume CGA
- jmp CEG_Assume_EGA ; Try default of EGA for non-PC type machines
-
- ; What this really means is that we don't
- ; assume working BIOS support for our "normal"
- ; complicated color screen update
- ; This certainly speeds up the screen on
- ; liquid crystal (and other ...) displays
-
- ; Regular PC -- give it a shot!
-
- CEG_PC: call NoInt ; No ints during this
- in al, 61h ; This port allows access to port 60h
- mov bl, al ; Save the original value from port 61h
- or al, 80h ; Turn on the bit making port 60h be switches
- out 61h, al ; Set this up
- in al, 60h ; Read system board switch bank 1
- xchg al, bl ; Save the switch settings, get back original
- ; value from port 61h
- out 61h, al ; Restore original value
- call OkInt ; Interrupts are permitted again
- mov al, bl ; Get back the switch settings
- jmp SHORT CEG_Common_code ; Join common code
-
- ; PC/XT -- have to use a slightly different method
-
- CEG_XT: call NoInt ; No interrupts during this stuff
- in al, 61h ; This port controls how we read port 62h
- mov bl, al ; Save the original value from port 61h
- or al, 40h ; Force this bit on so we read the high half
- out 61h, al ; Set this up
- in al, 62h ; Read the high half of SW 1
- xchg al, bl ; Save the switch settings, get back original
- ; value from port 61h
- out 61h, al ; Restore original value
- call OkInt ; Interrupts are permitted again
- mov al, bl ; Get back the switch settings
- jmp SHORT CEG_Common_code ; Join common code
-
- ; PC AT, look into CMOS battery powered RAM for configuration info
-
- CEG_AT: mov al, 14h ; CMOS register holding equip flags
- out 70h, al ; Tell CMOS chip which register we want
- in al, 71h ; Read the equip flags
-
- PUBLIC CEG_Common_code
-
- CEG_Common_code:
- test al, 30h ; Are either of these switches set?
- jnz CEG_Done ; Not EGA
-
- CEG_Assume_EGA:
- mov Which_card, 2 ; Code for EGA
-
- CEG_Done: ret ; Go home
-
- Check_for_EGA ENDP
-
-
- PUBLIC Switch_video_pages
-
- Switch_video_pages:
- mov ax, 0B000h ; Address of monochrome card
- cmp Which_card, 0 ; Monochrome card?
- je SVP_Set ; Yes
-
- mov ax, 0B800h ; Address of color card
- cmp Which_card, 2 ; EGA?
- je SVP_Set ; Yes
-
- ; True color card, really switch pages
-
- mov al, 1 ; Get a one
- sub al, Which_page ; 1 minus 0 = 1, 1 minus 1 = 0
- mov Which_page, al ; Store for next time
- mov ah, 5 ; Code to switch video pages
- int Screen ; Tell ROM BIOS to switch pages now
-
- mov bl, Which_page ; Get number of page we are on
- sub bh, bh ; Zero top half of word
- shl bx, 1 ; Double for word offset
- mov ax, Video_page_addresses[bx] ; Address of the screen memory
-
- SVP_Set:
- mov Screen_pointer, ax ; Set up this pointer
- ret ; Done here
-
- PUBLIC Go_to_page_zero
-
- Go_to_page_zero:
-
- sub al, al ; Get a zero
- mov Which_page, al ; Store it as the page we are on
- mov ah, 5 ; Code to switch video pages
- int Screen ; Tell ROM BIOS to switch pages now
-
- mov ax, 0B000h ; Address of monochrome card's only page
- cmp Which_card, 0 ; Mono card?
- je PG0_Mono ; Monochrome
-
- mov ax, 0B800h ; Addr of color card page zero (maybe EGA)
-
- PG0_Mono:
- mov Screen_pointer, ax ; Set up pointer
- ret
-
- PUBLIC Blank_current_page
-
- Blank_current_page:
- mov ax, 600h ; Code to blank entire window
- mov bh, 7 ; Normal video attribute
- sub cx, cx ; Make a zero as upper left corner
- mov dx, (100h * (Number_of_rows_PC - 1) ) + Highest_column
- ; Use real lower right corner of screen
- int Screen ; Ask BIOS to blank it for us
- ret ; Done here
-
-
- ; Turn video beam off and on to prevent screen snow on color card
-
- Beam_Off PROC
-
- cmp CRT_Mode, 7 ; BW?
- je BOF_1 ; Yes
-
- push es ; Save reg
- sub ax, ax ; Make a zero
- mov es, ax ; Address low memory
- mov al, es:[465h] ; Pick up DOS's value for this
- mov Beam_status, al ; Save for later
- and al, NOT Video_enable ; Mask off the video bit
- mov dx, Mode_control_port ; Address of CRT control port
- out dx, al ; Turn off the video now
- pop es ; Restore saved reg
-
- BOF_1: ret
-
- Beam_Off ENDP
-
- Beam_On PROC
-
- cmp CRT_Mode, 7 ; BW?
- je BON_1 ; Yes
-
- mov al, Beam_status ; Pick up saved beam state
- mov dx, Mode_control_port ; Address of CRT control port
- out dx, al ; Restore the old state
-
- BON_1: ret
-
- Beam_On ENDP
-
-
- ; this is called by Kermit initialization. It checks the
- ; number of disks on the system, sets the drives variable
- ; appropriately. Returns normally
-
- DoDisk_PC PROC NEAR
- int mconf ; Get equipment configuration
- mov ah,al ; Store AL value for a bit
- and al,01H ; First, look at bit 0
- jz dodsk0 ; No disk drives -- forget it
- mov al,ah ; Get back original value
- mov cl,6 ; Shift over bits 6 and 7
- shr al,cl ; To positions 0 and 1
- inc al ; Want 1 thru 4 (not 0 thru 3)
- mov drives,al ; Remember how many
- ret
- dodsk0: mov ah,prstr ; Print a warning message
- mov dx,offset erms20 ; I'm not sure if things will
- int dos ; work with only a cassette
- mov drives,0 ; Say there aren't any drives
- ret
- DoDisk_PC ENDP
-
- ; show the definition of a key. The terminal argument block (which contains
- ; the address and length of the definition tables) is passed in ax
- ; Returns a string to print in AX, length of same in CX
- ; Returns normally
- ShowKey_PC proc near
- push es
- push ax ; save the ptr
- mov bx,ds
- mov es,bx ; address data segment
- cld
- showk1: xor ah,ah
- int keyb ; read a char
- push ax ; save the character
- call gss ; get shift state
- pop bx
- mov ah,al ; shift state to ah
- mov al,bh ; scan code to al
- push ax ; remember scan code
- mov di,offset shkbuf
- mov si,offset shkmsg
- mov cx,shkmln
- rep movsb ; copy in initial message
- call nout ; write out scan code
- mov si,offset shkms1
- mov cx,shkm1ln ; second message
- rep movsb
- pop ax ; get scan code back
- pop bx ; and terminal arg block
- mov cx,[bx].klen ; and length
- jcxz showk2 ; no table, not defined
- push di ; remember output ptr
- mov di,[bx].ktab ; get key table
- repne scasw ; search for a definition for this
- mov si,di ; remember result ptr
- pop di ; get output ptr back
- jne showk2 ; not defined, forget it
- sub si,[bx].ktab ; compute offset from beginning
- sub si,2 ; minus 2 for pre-increment
- add si,[bx].krpl ; get index into replacement table
- mov si,[si] ; pick up replacement
- mov cl,[si] ; get length
- mov ch,0
- inc si
- rep movsb ; copy into buffer
- showk2: mov ax,offset shkbuf ; this is buffer
- mov cx,di
- sub cx,ax ; length
- pop es
- ret ; and return
- ShowKey_PC endp
-
- ; Clear the input buffer. This throws away all the characters in the
- ; serial interrupt buffer. This is particularly important when
- ; talking to servers, since NAKs can accumulate in the buffer
- ; Returns normally
-
- ClrBuf_PC PROC NEAR
- call NoInt ; No interrupts during this
- mov ax,offset source
- mov srcpnt,ax
- mov savesi,ax
- mov count,0
- call OkInt
- ret
- ClrBuf_PC ENDP
-
- ; Clear to the end of the current line. Returns normally
-
- ClearL_PC PROC NEAR
- mov ah,3 ; Clear to end of line
- mov bh,0
- int bios ; Get current cursor position
- mov cx,dx
- mov dl,79
- mov ah,7
- mov al,0
- mov bh,7
- int bios
- ret
- ClearL_PC ENDP
-
- ; Put the char in AH to the serial port. This assumes the
- ; port has been initialized. Should honor xon/xoff. Skip returns on
- ; success, returns normally if the character cannot be written
-
- OutChr_PC:
- push cx ; Save initial cx
- mov bp,portval
- cmp ds:[bp].floflg,0 ; Are we doing flow control
- je outch2 ; No, just continue
-
- sti ; Make sure interrupts are ok
- mov cx, 4 ; Perform the inner loop this many times
-
- outcha: push cx ; Save outer loop counter
- xor cx, cx ; Clear inner loop counter
-
- outch1: cmp xofrcv, true ; Are we being held?
- jne outchb ; No - it's OK to go on
-
- loop outch1 ; Held, try for a while (inner loop)
-
- pop cx ; Restore outer loop counter
- loop outcha ; Restart inner loop
-
- mov xofrcv, false ; Timed out, force it off and fall thru
- jmp SHORT outch2 ; Join common code
-
- outchb: pop cx ; Flush saved outer loop counter
-
- outch2: push dx ; Save register
- sub cx,cx
- mov al,ah ; Parity routine works on AL
- call dopar ; Set parity appropriately
- mov ah,al ; Don't overwrite character with status
- mov dx,modem.mdstat ; Get port status
- outch3: in al,dx
- test al,20H ; Transmitter ready?
- jnz outch4 ; Yes
- loop outch3
- jmp outch5 ; Timeout
- outch4: mov al,ah ; Now send it out
- mov dx,modem.mddat
- out dx,al
- pop dx
- pop cx
- jmp rskp
- outch5: pop dx
- pop cx
- ret
-
- ; This routine blanks the screen. Returns normally
-
- CmBlnk_PC PROC NEAR ; This is stolen from the IBM example
- mov cx,0
- mov dx,184FH
- mov bh,7
- mov ax,600H
- int bios
- ret
- CmBlnk_PC ENDP
-
- ; Locate_PC: homes the cursor. Returns normally
-
- Locate_PC PROC NEAR
- mov dx,0 ; Go to top left corner of screen
- jmp PosCur_PC
- Locate_PC ENDP
-
- ; Write a line in inverse video (or Blue-on-White) at the
- ; bottom of the screen... Ptr to the line is passed in dx,
- ; line is terminated by a $. Returns normally
-
- PutMod_PC PROC
-
- mov bh,70h ; Inverse video
- cmp Force_mono, 0 ; Mono forced?
- jne PMD_1 ; Yes
-
- cmp Which_card, 0 ; Monochrome card?
- je PMD_1 ; Yes
-
- mov bh, 71h ; Use Blue on White on color card
-
- PMD_1: jmp Mode_common ; Use common code
-
- PutMod_PC ENDP
-
- ; Write a line in inverse video or Red-on-White at the
- ; bottom of the screen... Ptr to line is passed in dx,
- ; line is terminated by a $. Returns normally
-
- PutErr_PC PROC
-
- mov bh,70h ; Inverse video
- cmp Force_mono, 0 ; Mono forced?
- jne PER_1 ; Yes
-
- cmp Which_card, 0 ; Monochrome card?
- je PER_1 ; Yes
-
- mov bh, 74h ; Use Red on White on color card
-
- PER_1: jmp Mode_common ; Join common code
-
- PutErr_PC ENDP
-
- ; Common code for PutMod_PC and PutErr_PC
-
- Mode_common PROC
-
- push dx ; preserve message
- mov cx,1800h
- mov dx,184fh
- mov ax,600h ; scroll to clear the line
- int bios ; Do it
- mov dx,1800h ; now address line 24
- call PosCur_PC
- pop dx ; get message back
- call Write_to_standard_output ; Use standard routine to do this
- ; mov ah,prstr
- ; int dos ; write it out
- ret ; and return
-
- Mode_common ENDP
-
- ; clear the mode line written by PutMod_PC. Returns normally
- ClrMod_PC proc near
- mov cx,1800h
- mov dx,184fh
- mov ax,600h
- mov bh,7h
- int bios
- ret
- ClrMod_PC endp
-
- ; put a help message on the screen. This one uses reverse video..
- ; pass the message in ax, terminated by a null. Returns normally
- PutHlp_PC proc near
- push ax ; preserve this
- cld ; Forwards
- mov si,ax ; point to it
- mov dh,0 ; init counter
- puthl1: lodsb ; get a byte
- cmp al,lf ; linefeed?
- jne puthl2 ; no, keep going
- inc dh ; count it
- jmp puthl1 ; and keep looping
- puthl2: cmp al,0 ; end of string?
- jne puthl1 ; no, keep going
- mov ax,600h ; scroll to clear window
- xor cx,cx ; from top left
- mov dl,4fh ; to bottom right of needed piece
- mov bh, 70h ; Inverse video
- cmp Force_mono, 0 ; Mono forced?
- jne PHP_1 ; Yes
-
- cmp Which_card, 0 ; Monochrome card?
- je PHP_1 ; Yes
-
- mov bh, 1Eh ; Use Yellow on Blue on color card
-
- PHP_1: int bios
- call Locate_PC ; home cursor
- pop si ; point to string again
- puthl3: lodsb ; get a byte
- cmp al,0 ; end of string?
- je puthl4 ; yes, stop
- mov ah,14
- int bios ; else write to screen
- jmp puthl3 ; and keep going
- puthl4: call ClrMod_PC ; Erase any mode line already there
- mov dx,24 * 100H ; go to last line
- jmp PosCur_PC ; position and return
- PutHlp_PC endp
-
- %OUT >> About half way through source file
-
- ; Set the baud rate for the current port, based on the value
- ; in the portinfo structure. Returns normally
-
- DoBaud_PC PROC NEAR
- mov bp,portval
- mov temp1,ax ; Don't overwrite previous rate. [25]
- mov ax,ds:[bp].baud ; Check if new rate is valid. [25]
- mov tmp,2
- mul tmp ; Get index into baud table
- mov bx,offset bddat ; Start of table
- add bx,ax
- mov ax,[bx] ; The data to output to port
- cmp ax,0FFH ; Unimplemented baud rate
- jne dobd0
- mov ax,temp1 ; Get back orginal value
- mov ds:[bp].baud,ax ; Leave baud rate as is
- mov ah,prstr
- mov dx,offset badbd ; Give an error message
- int dos
- ret
- dobd0: mov temp1,ax ; Remember value to output. [25]
- mov dx,modem.mdcom ; LCR -- Initialize baud rate. [19b]
- in al,dx
- mov bl,al
- or ax,80H
- out dx,al
- mov dx,modem.mddat ; [19b]
- mov ax,temp1
- out dx,al
- inc dx
- mov al,ah
- out dx,al
- mov dx,modem.mdcom ; [19b]
- mov al,bl
- out dx,al
- ret
- DoBaud_PC ENDP
-
- ; Get the current baud rate from the serial card and set it
- ; in the portinfo structure for the current port. Returns normally
- ; This is used during initialization
-
- GetBaud_PC PROC NEAR
- mov dx,modem.mdcom ; Get current Line Control Register value
- in al,dx
- mov bl,al ; Save it
- or ax,80H ; Turn on to access baud rate generator
- out dx,al
- mov dx,modem.mddat ; Divisor latch
- inc dx
- in al,dx ; Get hi order byte
- mov ah,al ; Save here
- dec dx
- in al,dx ; Get lo order byte
- push ax
- mov dx,modem.mdcom
- mov al,bl ; Restore old value
- out dx,al
- pop ax
- cmp ax,0FFFFH ; Who knows what this is
- je getb2
- mov bx,offset bddat ; Find rate's offset into table
- mov cl,0 ; Keep track of index
- getb0: cmp ax,[bx]
- je getb1
- inc cl
- cmp cl,baudsiz ; At the end of the list
- jge getb2
- add bx,2
- jmp getb0
- getb1: mov ch,0
- mov bp,portval
- mov ds:[bp].baud,cx ; Set baud rate
- ret
- getb2: mov ah,prstr
- mov dx,offset erms40
- int dos
- ret
- GetBaud_PC ENDP
-
- ; skip returns if no character available at port,
- ; otherwise returns with char in al, # of chars in buffer in dx
- PrtChr_PC PROC NEAR
- cld ; Forwards
- call chkxon ; see if we need to xon
- cmp count,0
- jnz prtch2
- jmp rskp ; No data - check console
- prtch2: mov si,savesi
- lodsb ; get a byte
- cmp si,offset source + bufsiz ; bigger than buffer?
- jb prtch1 ; no, keep going
- mov si,offset source ; yes, wrap around
- prtch1: dec count
- mov savesi,si
- mov dx,count ; return # of chars in buffer
- ret
- PrtChr_PC ENDP
-
- ; local routine to see if we have to transmit an xon
- chkxon proc near
- push bx
- mov bx,portval
- cmp [bx].floflg,0 ; doing flow control?
- je chkxo1 ; no, skip all this
- cmp xofsnt,false ; have we sent an xoff?
- je chkxo1 ; no, forget it
- cmp count,XOFF_trigger_count ; below trigger?
- jae chkxo1 ; no, forget it
- mov ax,[bx].flowc ; ah gets xon
- call OutChr_PC ; send it
- nop
- nop
- nop ; in case it skips
- mov xofsnt,false ; remember we've sent the xon
- chkxo1: pop bx ; restore register
- ret ; and return
- chkxon endp
-
- ; Send a break out the current serial port. Returns normally
- SENDBR_PC PROC
- push cx
- push dx
- push ax
- xor cx,cx ; Clear loop counter
- mov dx,brkadr ; Port address. [19b]
- in al,dx ; Get current setting
- or al,brkval ; Set send-break bit(s)
- out dx,al ; Start the break
- push ax
- mov ax,275 ; # of ms to wait
- call pcwait ; hold break for desired interval
- pop ax
- xor al,brkval ; Clear send-break bit(s)
- out dx,al ; Stop the break
- pop ax
- pop dx
- pop cx
- ret ; And return
- SENDBR_PC ENDP
-
- ; Wait for the # of milliseconds in ax
- ; Thanks to Bernie Eiben for this one
- pcwait proc near
- mov cx,240 ; inner loop counter for 1 millisecond
- cmp PC_Subtype, 3 ; Is this an AT?
- jne pcwai1 ; No
-
- mov cx, 4*240 ; It is an AT, use a much higher value
-
- pcwai1: sub cx,1 ; inner loop takes 20 clock cycles
- jnz pcwai1
- dec ax ; outer loop counter
- jnz pcwait ; wait another millisecond
- ret
- pcwait endp
-
- ; Position the cursor according to contents of DX:
- ; DH contains row, DL contains column. Returns normally
-
- PosCur_PC PROC NEAR
- mov ah,2 ; Position cursor
- mov bh,0
- int bios
- ret
- PosCur_PC ENDP
-
- ; Delete a character from the terminal. This works by printing
- ; backspaces and spaces. Returns normally
-
- DoDel_PC PROC NEAR
- mov ah,prstr
- mov dx,offset delstr ; Erase weird character
- int dos
- ret
- DoDel_PC ENDP
-
- ; Move the cursor to the left margin, then clear to end of line
- ; Returns normally
-
- CtlU_PC PROC NEAR
- mov ah,prstr
- mov dx,offset clrlin
- int dos
- call ClearL_PC
- ret
- CtlU_PC ENDP
-
- ; set the current port
-
- Coms_PC PROC NEAR
- mov dx,offset comptab
- mov bx,0
- mov ah,cmkey
- call comnd
- jmp r
- push bx
- mov ah,cmcfm
- call comnd ; Get a confirm
- jmp comx ; Didn't get a confirm
- nop
- pop bx
- mov flags.comflg,bl ; Set the comm port flag
- cmp flags.comflg,1 ; Using Com 1?
- jne coms0 ; Nope
- mov ax,offset port1
- mov portval,ax
- mov modem.mddat,MDMDAT1 ; Set COM1 defaults
- mov modem.mdstat,MDMSTS1
- mov modem.mdcom,MDMCOM1
- mov modem.mddis,MDMINTC
- mov modem.mden,MDMINTO
- mov modem.mdmeoi,EOICOM
- mov modem.mdintv,MDMINTV
- mov brkadr,MDMCOM1
- ret
- coms0: mov ax,offset port2
- mov portval,ax
- mov modem.mddat,MDMDAT2 ; Set COM2 defaults
- mov modem.mdstat,MDMSTS2
- mov modem.mdcom,MDMCOM2
- mov modem.mddis,MDINTC2
- mov modem.mden,MDINTO2
- mov modem.mdmeoi,EOICOM2
- mov modem.mdintv,MDINTV2
- mov brkadr,MDMCOM2
- ret
- comx: pop bx
- ret
- Coms_PC ENDP
-
- ; Set heath emulation on/off
-
- VTS_PC PROC NEAR
- mov dx,offset ontab
- mov bx,0
- mov ah,cmkey
- call comnd
- jmp r
- push bx
- mov ah,cmcfm
- call comnd ; Get a confirm
- jmp vt0 ; Didn't get a confirm
- nop
- pop bx
- mov flags.vtflg,bl ; Set the VT52 emulation flag
- ret
- vt0: pop bx
- ret
- VTS_PC ENDP
-
-
- ; initialization for using serial port. This routine performs
- ; any initialization necessary for using the serial port, including
- ; setting up interrupt routines, setting buffer pointers, etc
- ; Doing this twice in a row should be harmless (this version checks
- ; a flag and returns if initialization has already been done)
- ; SerRst_PC below should restore any interrupt vectors that this changes
- ; Returns normally
-
- SerIni_PC PROC
-
- push es
- cmp portin, 0 ; Did we initialize port already? [21c]
- jne serin0 ; Yes, so just leave. [21c]
-
- call NoInt ; Disable interrupts
-
- xor ax,ax ; Address low memory
- mov es,ax
-
- mov bx,modem.mdintv ; Save serial card interrupt vector. [19b]
- mov ax,es:[bx]
- mov savsci,ax
-
- mov ax,offset SerInt ; And point it to my routine
- mov es:[bx],ax
-
- add bx,2 ; Save CS register too. [19b]
-
- mov ax,es:[bx]
- mov savscs,ax
- mov es:[bx],cs
-
- mov portin,1 ; Remember port has been initialized
-
- call ClrBuf_PC ; Clear input buffer
-
- mov ax,modem.mdstat
- mov mst,ax ; Use this address for status
-
- mov ax,modem.mddat
- mov mdat,ax ; Use this address for data
-
- mov al,modem.mdmeoi
- mov mdeoi,al ; Use to signify end-of-interrupt
-
- in al,21H ; Set up 8259 interrupt controller
- and al,modem.mden ; Enable INT3 or INT4
- out 21H,al
-
- mov dx,modem.mdcom ; Set up the serial card
- mov al,3
- out dx,al
-
- mov dl,0F9h
- mov al,1 ; Set up interrupt enable register
- out dx,al
-
- mov dl,0FCh ; Enable interrupts from serial card
- mov al,0Bh
- out dx,al
-
- call OkInt ; Allow interrupts
-
- mov dl,0F8h
- in al,dx
-
- serin0: pop es
- ret
-
- SerIni_PC ENDP
-
-
- ; Reset the serial port. This is the opposite of SerIni_PC. Calling
- ; this twice without intervening calls to SerIni_PC should be harmless.
- ; Returns normally.
-
- SerRst_PC PROC
-
- push es ; Preserve this
- cmp portin,0 ; Reset already?
- je srst1 ; Yes, just leave
-
- call NoInt ; Disable interrupts
-
- mov dx, 03FCh ; Disable modem interrupts, assume port 1
- cmp flags.comflg, 1 ; Is it port 1?
- je srst0 ; Yes
-
- mov dh, 2 ; Port 2
-
- srst0: mov al, 3
- out dx,al
-
- in al, 21h ; Interrupt controller
-
- or al, modem.mddis ; Inhibit IRQ3 or IRQ4
- out 21H, al
-
- xor bx, bx ; Address low memory
- mov es, bx
-
- mov bx, modem.mdintv ; Restore the serial card int vector
- mov ax, savsci
- mov es:[bx], ax
-
- add bx, 2 ; Restore CS too
-
- mov ax, savscs
- mov es:[bx], ax
- mov portin, 0 ; Reset flag
-
- call OkInt
-
- srst1: pop es
- ret ; All done
-
- SerRst_PC ENDP
-
-
- Drop_DTR_PC PROC
-
- push ax ; Save regs
- push dx
-
- mov dx, 03FCh ; Port for COM1 modem control register
- cmp flags.comflg, 1 ; Using port 1 ?
- je DTR_0 ; Yes, continue
-
- mov dh, 2 ; Using COM2
-
- DTR_0: sub al, al ; Clear this register
- out dx,al ; Drop DTR now
-
- pop dx ; Restore regs
- pop ax
- ret ; Done here
-
- Drop_DTR_PC ENDP
-
-
- ; Serial port interrupt routine
-
- SERINT PROC FAR
-
- ; Save some registers ...
- push dx
- push ds
- push ax
- push es
-
- mov ax, SEG DataS ; Address data segment
- mov ds, ax ; Set up ds
- mov es, ax ; and es
-
- mov dx, mst ; Line Status Register (LSR), for port 1 or 2
- in al, dx
-
- test al, mdminp ; Data available?
- jz Return_2 ; Nope
-
- mov dx, mdat ; Get the data
- in al,dx
-
- cmp Count, BufSiz ; Room left in buffer?
- jae Return_2 ; No room left, don't overstore!!
-
- ; Save more registers ...
- push bx
- push di
- push bp
-
- mov bp, portval
- cmp ds:[bp].floflg, 0 ; Doing flow control?
- je srint2 ; Nope
-
- mov bx, ds:[bp].flowc ; Flow control char (BH = XON, BL = XOFF)
- cmp al, bl ; Is it an XOFF?
- jne srint1 ; Nope, go on
-
- mov xofrcv, true ; Set the flag
- jmp SHORT RetInt
-
- srint1: cmp al, bh ; Get an XON?
- jne srint2 ; No, go on
-
- mov xofrcv, false ; Clear our flag
- ; jmp SHORT RetInt
-
- RetInt:
-
- ; Restore some saved registers ...
- pop bp
- pop di
- pop bx
-
- Return_2:
- sti ; Allow ints now
- mov al, mdeoi ; Send End-of-Interrupt ...
- out intcon1, al ; to 8259
-
- ; Restore other saved registers ...
- pop es
- pop ax
- pop ds
- pop dx
-
- iret ; Return from interrupt
-
- srint2: cld ; Store forwards
- mov di, srcpnt ; Where to store it
- stosb ; Store it
-
- cmp di, OFFSET Source + BufSiz
- jb srint3 ; Not past end ...
-
- mov di, OFFSET Source ; Wrap buffer around
-
- srint3: inc count ; Bump the count
- mov srcpnt, di ; Store the updated pointer
-
- cmp ds:[bp].floflg, 0 ; Doing flow control?
- je RetInt ; No, just leave
-
- cmp count, XOFF_trigger_count ; Past the high trigger point?
- jbe RetInt ; No, we're within our limit
-
- cmp xofsnt, true ; Have we sent an XOFF?
- je RetInt ; Yes
-
- mov ah,bl ; Get the XOFF
- push cx ; OutChr_PC clobbers cx, we're not allowed to
- call OutChr_PC ; Send it
- nop
- nop
- nop
- pop cx ; Restore cx
-
- mov xofsnt,true ; Remember we sent it
- jmp SHORT RetInt ; Branch upwards into common code
-
- SERINT ENDP
-
-
- ; Produce a short beep. The PC DOS bell is long enough to cause a loss
- ; of data at the port. Returns normally
-
- Beep_PC PROC NEAR
- mov al,10110110B ; Gen a short beep (long one losses data.)
- out timer+3,al ; Code snarfed from Technical Reference
- mov ax,533H
- out timer+2,al
- mov al,ah
- out timer+2,al
- in al,port_b
- mov ah,al
- or al,03
- out port_b,al
- sub cx,cx
- mov bl,1
- beep0: loop beep0
- dec bl
- jnz beep0
- mov al,ah
- out port_b,al
- ret
- Beep_PC ENDP
-
- ; put the number in ax into the buffer pointed to by di. Di is updated
- nout proc near
- cld ; Forwards
- mov dx,0 ; high order is always 0
- mov bx,10
- div bx ; divide to get digit
- push dx ; save remainder digit
- or ax,ax ; test quotient
- jz nout1 ; zero, no more of number
- call nout ; else call for rest of number
- nout1: pop ax ; get digit back
- add al,'0' ; make printable
- stosb ; drop it off
- ret ; and return
- nout endp
-
-
- ; Jumping to this location is like retskp. It assumes the instruction
- ; after the call is a jmp addr
-
- RSKP PROC NEAR
- pop bp
- add bp,3
- push bp
- ; ret
- RSKP ENDP
-
- ; Jumping here is the same as a ret
-
- R PROC NEAR
- ret
- R ENDP
-
- Code ENDS
-
- END
-